package com.starblink.android.basic.util

import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.*

class FlowCountDownTimer constructor(private var time: Int) {
    constructor(
        time: Int,
        callBack: (time: Int) -> Unit, //每隔1s回调一次callBack()方法
        onFinish: (time: Int) -> Unit  //结束回调
    ) : this(time) {
        mTime = time
        mCallBack = callBack
        mOnFinish = onFinish
    }
    //总时间
    private var mTime: Int = time
    //已走事件
    private var tTime = 0
    private var mCallBack: (time: Int) -> Unit? = {}
    private var mOnFinish: (time: Int) -> Unit? = {}

    private var finish = true//计时器是否已结束
    private var clean = true //计时状态 是否为清除

    private val intFlow = flow {
        finish = false
        while (!clean && tTime < mTime) {//当前为计时状态，且时间未执行完毕
            tTime++
            emit(mTime - tTime)//发送事件到下一步
            delay(1000)
        }
    }.flowOn(Dispatchers.Main)//定义处理事件的线程
        .onEach { mCallBack.invoke(it) }//接收事件
        .onCompletion { cause -> //结束事件判断
            if (cause == null) {
                if(!clean){
                    // 如果手动取消了倒计时，不再回调mOnFinish方法
                    mOnFinish.invoke(0)
                }
                clean = true
                finish = true
            }
        }




    /**
     * 开始倒计时
     * @param time 倒计时时长
     * @param callBack 倒计时反馈
     * @param onFinish 结束事件
     */
    //开始计时，判断当前是否存在计时未走完，存在则更新，不存在则启动
    fun start(
        time: Int = this.time,
        callBack: (time: Int) -> Unit,
        onFinish: (time: Int) -> Unit
    ) {
        clean = false
        tTime = 0
        mTime = time
        mCallBack = callBack
        mOnFinish = onFinish
        if (finish) {
            //开始发送事件，设置执行线程
            intFlow.launchIn(CoroutineScope(Dispatchers.Main))

        }
    }



    //开始计时，判断当前是否存在计时未走完，存在则更新，不存在则启动
    fun start() {
        clean = false
        tTime = 0
        if (finish) {
            mTime = time
            intFlow.launchIn(CoroutineScope(Dispatchers.Main)) //保证在一个协程中执行
        }
    }

    /**
     * 清除倒计时
     */
    fun cancel() {
        tTime = 0   //清除已走时间
        clean = true//停止时间标识设为停止
    }
}